﻿using System;
using System.Collections.ObjectModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shell;
using Automator.Classes;
using Automator.Runtime;
using Automator.Runtime.Classes;
using Automator.Runtime.Wizards;
using Automator.Tasks.Core;
using Automator.Windows;
using AvalonDock;

namespace Automator
{
    public partial class MainWindow: Window
    {
        
        #region CommonCommands

        #region Executed
        
        public void SaveCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            if (dockingManager.ActiveDocument is SolutionDocument)
                SaveEntity(solution);
            else if (dockingManager.ActiveDocument is WorkflowDocument)
                SaveEntity((dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance);
        }
        
        public void SaveAsCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            if (dockingManager.ActiveDocument is SolutionDocument)
                SaveEntity(solution, true);
            else if (dockingManager.ActiveDocument is WorkflowDocument)
                SaveEntity((dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance, true);
        }
        
        public void SaveAllCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            foreach (Workflow workflow in solution.Workflows)
                SaveEntity(workflow);
            SaveEntity(solution);
        }
        
        #endregion
        
        #region CanExecute
        
        public void SaveCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = ((dockingManager.ActiveDocument is WorkflowDocument) &&
                            (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.State != EntityExecutingState.Executing) ||
                ((dockingManager.ActiveDocument is SolutionDocument) && solution.State != EntityExecutingState.Executing);
        }
        
        #endregion

        #endregion
        
        #region SolutionCommands

        #region NewSolutionCommand

        public void NewSolutionCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            if (SaveChanges())
            {
                ObservableCollection<DocumentContent> docsToClose = new ObservableCollection<DocumentContent>();
                foreach (DocumentContent doc in dockingManager.Documents)
                    if (doc is WorkflowDocument)
                        docsToClose.Add(doc);
                foreach (WorkflowDocument doc in docsToClose)
                    doc.Close();

                solution.ClearWorkflows();
                solution.Log.Clear();
                solution.FileName = String.Empty;
                solution.ClearId();
                solution.Modified = false;
                Workflow.ResetInternalIndex();
            }
        }

        #endregion

        #region OpenSolutionCommand

        public void OpenSolutionCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            OpenWindow window = new OpenWindow(DocumentTypes.Solution);
            window.Owner = this;
            if (window.ShowDialog().Value)
            {
                AutomatorCommands.NewSolution.Execute(null, null);
                if (window.rbFileSystem.IsChecked.Value)
                {
                    solution.Load(window.edtFileName.Text);
                }
                else if (window.rbDatabase.IsChecked.Value)
                {
                    DataRowView rv = window.gridEntities.SelectedItem as DataRowView;
                    solution.Load(Guid.Parse(rv.Row["Id"].ToString()), rv.Row["Name"].ToString(), rv.Row["XmlData"].ToString());
                }
            }
        }

        #endregion
        
        #endregion

        #region WorkflowCommands

        #region NewWorkflowCommand
        
        public void NewWorkFlowCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            Workflow workflow = solution.CreateWorkflow();
            AddWorkflowDocument(workflow);
        }
        
        #endregion
        
        #region RunWorkflowCommand
        
        public void RunWorkflowCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            if (dockingManager.ActiveDocument is WorkflowDocument)
            {
                taskbarInfo.Overlay = (ImageSource)this.Resources["overlayRun"];
                taskbarInfo.ProgressState = TaskbarItemProgressState.Indeterminate;
                WaitForm.IsBusy = true;
                (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.Run();
                WaitForm.IsBusy = false;
                taskbarInfo.ProgressState = TaskbarItemProgressState.None;
                taskbarInfo.Overlay = null;
            }
        }
        
        #endregion
        
        #region ResetWorkflowCommand

        public void ResetWorkflowCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            if (dockingManager.ActiveDocument is WorkflowDocument)
                (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.Reset();
        }

        #endregion
        
        #region EditWorkflowCommand
        
        public void EditWorkflowCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            if (dockingManager.ActiveContent is SolutionDocument)
            {
                var item = (dockingManager.ActiveContent as SolutionDocument).WorkflowTree.SelectedItem;
                if (item is Workflow)
                    AddWorkflowDocument(item as Workflow);
            }
        }
        
        #endregion
        
        #region RemoveWorkflowCommand
        
        public void RemoveWorkflowCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            Workflow workflow = null;
            
            if (dockingManager.ActiveContent is SolutionDocument)
            {
                var item = (dockingManager.ActiveContent as SolutionDocument).WorkflowTree.SelectedItem;
                if (item is Workflow)
                    workflow = item as Workflow;
            }
            else if (dockingManager.ActiveContent is WorkflowDocument)
                workflow = (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance;
            else return;
            
            if (workflow != null)
            {
                MessageBoxResult result = Microsoft.Windows.Controls.MessageBox.Show(
                    String.Format("Remove {0} from solution?", workflow.Name.Replace("*",String.Empty)),
                    "Confirmation",
                    MessageBoxButton.YesNo);
                
                if (result == MessageBoxResult.Yes)
                    ExecuteRemoveWorkflow(workflow);
            }
        }
        
        #endregion
        
        #region DeleteWorkflowCommand
        
        public void DeleteWorkflowCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            Workflow workflow = null;
            
            if (dockingManager.ActiveContent is SolutionDocument)
            {
                var item = (dockingManager.ActiveContent as SolutionDocument).WorkflowTree.SelectedItem;
                if (item is Workflow)
                    workflow = item as Workflow;
            }
            else if (dockingManager.ActiveContent is WorkflowDocument)
                workflow = (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance;
            else return;
            
            if (workflow != null)
            {
                MessageBoxResult result = Microsoft.Windows.Controls.MessageBox.Show(
                    String.Format("Delete {0} permanently?", workflow.Name.Replace("*",String.Empty)),
                    "Confirmation",
                    MessageBoxButton.YesNo);
                
                if (result == MessageBoxResult.Yes)
                {
                    ExecuteRemoveWorkflow(workflow);
                    if (solution.Workflows.IndexOf(workflow) < 0)
                    {
                        if (!workflow.Id.Equals(Guid.Empty))
                            DataAccess.Delete(workflow.Id);
                        else if (!String.IsNullOrEmpty(workflow.FileName))
                            File.Delete(workflow.FileName);
                    }
                }
            }
        }
        
        #endregion
        
        #region OpenWorkflowCommand
        
        public void OpenWorkflowCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            OpenWindow window = new OpenWindow(DocumentTypes.Workflow);
            window.Owner = this;
            if (window.ShowDialog().Value)
            {
                WaitForm.IsBusy = true;
                try
                {
                    Automator.Runtime.Classes.DoEvents.Push();
                    Workflow workflow = solution.CreateWorkflow();
                    if (window.rbFileSystem.IsChecked.Value)
                    {
                        workflow.Load(window.edtFileName.Text);
                    }
                    else if (window.rbDatabase.IsChecked.Value)
                    {
                        DataRowView rv = window.gridEntities.SelectedItem as DataRowView;
                        workflow.Load(Guid.Parse(rv.Row["Id"].ToString()), rv.Row["Name"].ToString(), rv.Row["XmlData"].ToString());
                    }
                    AddWorkflowDocument(workflow);
                }
                finally
                {
                    WaitForm.IsBusy = false;
                }
            }
        }
        
        #endregion
        
        private void ExecuteRemoveWorkflow(Workflow workflow)
        {
            ObservableCollection<DocumentContent> docsToClose = new ObservableCollection<DocumentContent>();
            foreach (DocumentContent doc in dockingManager.Documents)
                if (doc is WorkflowDocument && (doc as WorkflowDocument).WorkflowInstance.Equals(workflow))
                    docsToClose.Add(doc);
            foreach (WorkflowDocument doc in docsToClose)
                doc.Close();
            
            solution.RemoveWorkflow(workflow);
        }

        public void WorkflowCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = ((dockingManager.ActiveDocument is WorkflowDocument) &&
                            (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.Tasks.Count > 0 &&
                            (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.State != EntityExecutingState.Executing);
        }
        
        public void SolutionWorkflowCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = (((dockingManager.ActiveContent is SolutionDocument) &&
                             (dockingManager.ActiveContent as SolutionDocument).WorkflowTree.Items.Count > 0 &&
                             (dockingManager.ActiveContent as SolutionDocument).WorkflowTree.SelectedItem != null &&
                             (dockingManager.ActiveContent as SolutionDocument).WorkflowTree.SelectedItem is Workflow));
        }

        #endregion

        #region TaskCommands

        #region RunTaskCommand
        
        public void RunTaskCommandExecuted(object sender, RoutedEventArgs e)
        {
            if (dockingManager.ActiveDocument is WorkflowDocument)
            {
                Task task = (dockingManager.ActiveDocument as WorkflowDocument).TasksTree.SelectedItem as Task;
                WorkflowExecutionContext context = new WorkflowExecutionContext();
                context.RunDependencies = false;
                WaitForm.IsBusy = true;
                (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.RunTask(task, context);
                (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.State = EntityExecutingState.Completed;
                WaitForm.IsBusy = false;
            }
        }
        
        #endregion
        
        #region RunTaskWithDependenciesCommand
        
        public void RunTaskWithDependenciesCommandExecuted(object sender, RoutedEventArgs e)
        {
            if (dockingManager.ActiveDocument is WorkflowDocument)
            {
                Task task = (dockingManager.ActiveDocument as WorkflowDocument).TasksTree.SelectedItem as Task;
                WorkflowExecutionContext context = new WorkflowExecutionContext();
                WaitForm.IsBusy = true;
                (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.RunTask(task, context);
                (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.State = EntityExecutingState.Completed;
                WaitForm.IsBusy = false;
            }
        }
        
        #endregion
        
        #region AddTaskCommand

        public void AddTaskCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            if (dockingManager.ActiveDocument is WorkflowDocument)
            {
                Task newTask = NewTask();
                if (newTask != null)
                {
                    (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.Tasks.Add(newTask);
                    (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.Modified = true;
                }
            }
        }
        
        public void AddTaskCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = dockingManager.ActiveDocument is WorkflowDocument;
        }

        #endregion
        
        #region AddDependencyCommand

        public void AddDependencyCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            _isDragging = true;
            if (dockingManager.ActiveDocument is WorkflowDocument)
            {
                Task task = (dockingManager.ActiveDocument as WorkflowDocument).TasksTree.SelectedItem as Task;
                Task newTask = NewTask();
                if (newTask != null)
                {
                    task.AddDependency(newTask);
                    (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.Modified = true;
                }
            }
            _isDragging = false;
        }
        
        public void AddDependencyCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = (dockingManager.ActiveDocument is WorkflowDocument &&
                            (dockingManager.ActiveDocument as WorkflowDocument).TasksTree.SelectedItem != null &&
                            ((dockingManager.ActiveDocument as WorkflowDocument).TasksTree.SelectedItem as Task).CanHaveDependencies);
        }

        #endregion
        
        #region EditTaskCommand
        
        public void EditTaskCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            if (dockingManager.ActiveDocument is WorkflowDocument)
                if (((dockingManager.ActiveDocument as WorkflowDocument).TasksTree.SelectedItem as Task).EditTask())
                    (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.Modified = true;
            
        }
        
        #endregion
        
        #region DeleteTaskCommand

        public void DeleteTaskCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            if (dockingManager.ActiveDocument is WorkflowDocument)
            {
                Task task = (dockingManager.ActiveDocument as WorkflowDocument).TasksTree.SelectedItem as Task;
                if (Microsoft.Windows.Controls.MessageBox.Show(
                    (task.DependentTasks.Count > 0) ? "Are you sure to delete selected Task with all its dependencies?"
                    : "Are you sure to delete selected Task?", "Delete Task", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
                {
                    if (task.ParentTask != null)
                    {
                        Task parent = task.ParentTask;
                        parent.RemoveDependency(task);
                    }
                    else
                        if (dockingManager.ActiveDocument is WorkflowDocument)
                            (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.Tasks.Remove(task);
                    (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.Modified = true;
                }
            }
        }

        #endregion
        
        #region MoveTaskUpCommand
        
        public void MoveTaskUpCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;
            MoveTask(
                (dockingManager.ActiveDocument as WorkflowDocument).TasksTree.SelectedItem as Task,
                MoveTaskDirection.Up,
                (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance);
        }
        
        #endregion
        
        #region MoveTaskDownCommand
        
        public void MoveTaskDownCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;
            MoveTask(
                (dockingManager.ActiveDocument as WorkflowDocument).TasksTree.SelectedItem as Task,
                MoveTaskDirection.Down,
                (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance);
        }
        
        #endregion
        
        #region CutTaskCommand
        
        public void CutTaskCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;
            Task task = (dockingManager.ActiveDocument as WorkflowDocument).TasksTree.SelectedItem as Task;
            
            if (task.ParentTask != null)
            {
                Task parent = task.ParentTask;
                parent.RemoveDependency(task);
            }
            else
                if (dockingManager.ActiveDocument is WorkflowDocument)
                    (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.Tasks.Remove(task);
            
            task.ParentTask = null;
            TaskClipboard.Add(task);
            (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.Modified = true;
        }
        
        #endregion
        
        #region CopyTaskCommand
        
        public void CopyTaskCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;
            Task task = (dockingManager.ActiveDocument as WorkflowDocument).TasksTree.SelectedItem as Task;
            TaskClipboard.Add(task.Clone());
        }
        
        #endregion
        
        #region PasteTaskCommand
        
        public void PasteTaskCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = (dockingManager.ActiveDocument is WorkflowDocument &&
                            TaskClipboard.Instance.Count > 0);
        }
        
        public void PasteTaskCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;
            TaskClipboard.Paste(TaskClipboard.Instance[0],
                                (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance);
        }
        
        #endregion
        
        /// <summary>
        /// Performs moving of the Task
        /// </summary>
        /// <param name="direction"></param>
        private void MoveTask(Task task, MoveTaskDirection direction, Workflow workflow)
        {
            Task parent = task.ParentTask;
            
            int index = (parent == null) ? workflow.Tasks.IndexOf(task) : parent.DependentTasks.IndexOf(task);
            int oldIndex = index;
            switch (direction)
            {
                case MoveTaskDirection.Up:
                    index--;
                    if (index < 0) index = 0;
                    break;
                case MoveTaskDirection.Down:
                    index++;
                    if (parent == null && index > workflow.Tasks.Count - 1) index = workflow.Tasks.Count - 1;
                    if (parent != null && index > parent.DependentTasks.Count - 1) index = parent.DependentTasks.Count - 1;
                    break;
            }
            
            if (index != oldIndex)
            {
                if (parent != null)
                {
                    parent.MoveDependency(oldIndex, index);
                }
                else
                {
                    workflow.Tasks.Move(oldIndex, index);
                }
                workflow.Modified = true;
            }
        }
        
        public void TaskCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = (dockingManager.ActiveDocument is WorkflowDocument &&
                            (dockingManager.ActiveDocument as WorkflowDocument).TasksTree.SelectedItem != null &&
                            (dockingManager.ActiveDocument as WorkflowDocument).WorkflowInstance.State != EntityExecutingState.Executing);
        }

        private Task NewTask()
        {
            NewTaskWindow window = new NewTaskWindow();
            window.Owner = Application.Current.MainWindow;
            window.ShowDialog();
            if (window.ResultTask != null)
            {
                Task newTask = window.ResultTask;
                newTask.EditTask();
                return newTask;
            }
            else return null;
        }
        
        #endregion

        #region HelpCommands

        #region AboutAutomatorCommand

        public void AboutAutomatorCommandExecuted(object sender, RoutedEventArgs e)
        {
            AboutWindow about = new AboutWindow();
            about.Owner = this;
            about.ShowDialog();
        }

        #endregion
        
        #region ProjectPageCommand
        
        public void ProjectPageCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            Process.Start(new ProcessStartInfo("http://automator.codeplex.com"));
        }
        
        #endregion
        
        #region OnlineDocumentationCommand
        
        public void OnlineDocumentationCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            Process.Start(new ProcessStartInfo("http://automator.codeplex.com/documentation"));
        }
        
        #endregion

        #endregion

        #region ViewCommands

        #region ViewOutputCommand

        public void ViewOutputCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            outputContent.Show(dockingManager);
        }

        #endregion
        
        #region ViewSolutionCommand
        
        public void ViewSolutionCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            solutionContent.Show(dockingManager);
        }
        
        #endregion

        #region ViewStartPageCommand

        public void ViewStartPageCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            AddStartPageDocument();
        }

        #endregion

        #region ViewClipboardCommand

        public void ViewClipboardCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            clipboardContent.Show(dockingManager);
        }

        #endregion

        #endregion

        #region ToolsCommands

        #region SqlSettingsCommand
        
        public void SqlSettingsCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            DbWizard wizard = new DbWizard(Automator.Runtime.Settings.SqlConnectionString);
            wizard.Owner = this;
            if (wizard.ShowDialog().Value)
            {
                Automator.Runtime.Settings.SqlConnectionString = wizard.Result;
                Automator.Runtime.Settings.SaveSettings();
            }
        }
        
        #endregion
        
        #region ProxySettingsCommand
        
        public void ProxySettingsCommandExecuted(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            ProxyWizard wizard = new ProxyWizard(Automator.Runtime.Settings.Proxy);
            wizard.Owner = this;
            if (wizard.ShowDialog().Value)
            {
                Automator.Runtime.Settings.Proxy = wizard.Result;
                Automator.Runtime.Settings.SaveSettings();
            }
        }        
        
        #endregion

        #endregion

        /// <summary>
        /// Registers all custom RoutedCommands with CommandManager, making them available to use
        /// </summary>
        private void RegisterCustomRoutedCommands()
        {
            
            #region CommonCommands
            
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(ApplicationCommands.Save, SaveCommandExecuted, SaveCommandCanExecute));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(ApplicationCommands.SaveAs, SaveAsCommandExecuted, SaveCommandCanExecute));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.SaveAll, new ExecutedRoutedEventHandler(SaveAllCommandExecuted)));
            
            #endregion
            
            #region SolutionCommands

            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.NewSolution, new ExecutedRoutedEventHandler(NewSolutionCommandExecuted)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.OpenSolution, new ExecutedRoutedEventHandler(OpenSolutionCommandExecuted)));

            #endregion

            #region WorkflowCommands

            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.NewWorkflow, new ExecutedRoutedEventHandler(NewWorkFlowCommandExecuted)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.RunWorkflow, new ExecutedRoutedEventHandler(RunWorkflowCommandExecuted),
                                                                          new CanExecuteRoutedEventHandler(WorkflowCommandCanExecute)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.ResetWorkflow, new ExecutedRoutedEventHandler(ResetWorkflowCommandExecuted),
                                                                          new CanExecuteRoutedEventHandler(WorkflowCommandCanExecute)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.EditWorkflow, new ExecutedRoutedEventHandler(EditWorkflowCommandExecuted),
                                                                          new CanExecuteRoutedEventHandler(SolutionWorkflowCanExecute)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.RemoveWorkflow, new ExecutedRoutedEventHandler(RemoveWorkflowCommandExecuted),
                                                                          new CanExecuteRoutedEventHandler(SolutionWorkflowCanExecute)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.DeleteWorkflow, new ExecutedRoutedEventHandler(DeleteWorkflowCommandExecuted),
                                                                          new CanExecuteRoutedEventHandler(SolutionWorkflowCanExecute)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.OpenWorkflow, new ExecutedRoutedEventHandler(OpenWorkflowCommandExecuted)));
            
            #endregion
            
            #region TaskCommands
            
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.RunTask, new ExecutedRoutedEventHandler(RunTaskCommandExecuted),
                                                                          new CanExecuteRoutedEventHandler(TaskCommandCanExecute)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.RunTaskWithDependencies, new ExecutedRoutedEventHandler(RunTaskWithDependenciesCommandExecuted),
                                                                          new CanExecuteRoutedEventHandler(TaskCommandCanExecute)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.AddTask, new ExecutedRoutedEventHandler(AddTaskCommandExecuted),
                                                                          new CanExecuteRoutedEventHandler(AddTaskCommandCanExecute)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.AddDependency, new ExecutedRoutedEventHandler(AddDependencyCommandExecuted),
                                                                          new CanExecuteRoutedEventHandler(AddDependencyCanExecute)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.EditTask, new ExecutedRoutedEventHandler(EditTaskCommandExecuted),
                                                                          new CanExecuteRoutedEventHandler(TaskCommandCanExecute)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.DeleteTask, new ExecutedRoutedEventHandler(DeleteTaskCommandExecuted),
                                                                          new CanExecuteRoutedEventHandler(TaskCommandCanExecute)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.MoveTaskUp, new ExecutedRoutedEventHandler(MoveTaskUpCommandExecuted),
                                                                          new CanExecuteRoutedEventHandler(TaskCommandCanExecute)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.MoveTaskDown, new ExecutedRoutedEventHandler(MoveTaskDownCommandExecuted),
                                                                          new CanExecuteRoutedEventHandler(TaskCommandCanExecute)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.Cut, new ExecutedRoutedEventHandler(CutTaskCommandExecuted),
                                                                          new CanExecuteRoutedEventHandler(TaskCommandCanExecute)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.Copy, new ExecutedRoutedEventHandler(CopyTaskCommandExecuted),
                                                                          new CanExecuteRoutedEventHandler(TaskCommandCanExecute)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.Paste, new ExecutedRoutedEventHandler(PasteTaskCommandExecuted),
                                                                          new CanExecuteRoutedEventHandler(PasteTaskCommandCanExecute)));
            
            #endregion
            
            #region HelpCommands
            
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.About, new ExecutedRoutedEventHandler(AboutAutomatorCommandExecuted)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.ProjectPage, new ExecutedRoutedEventHandler(ProjectPageCommandExecuted)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.OnlineDocumentation, new ExecutedRoutedEventHandler(OnlineDocumentationCommandExecuted)));
            
            #endregion

            #region ViewCommands

            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.ViewOutput, new ExecutedRoutedEventHandler(ViewOutputCommandExecuted)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.ViewSolution, new ExecutedRoutedEventHandler(ViewSolutionCommandExecuted)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.ViewStartPage, new ExecutedRoutedEventHandler(ViewStartPageCommandExecuted)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.ViewClipboard, new ExecutedRoutedEventHandler(ViewClipboardCommandExecuted)));

            #endregion
            
            #region ToolsCommands
                
            
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.SqlSettings, new ExecutedRoutedEventHandler(SqlSettingsCommandExecuted)));
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                                                       new CommandBinding(AutomatorCommands.ProxySettings, new ExecutedRoutedEventHandler(ProxySettingsCommandExecuted)));
            
            #endregion

        }
        
        private void SaveEntity(RuntimeEntity entity, bool IsSaveAs = false)
        {            
            try
            {
                // calling Save As dialog
                if (IsSaveAs)
                {
                    DocumentTypes docType = DocumentTypes.Workflow;
                    if (entity is Workflow) docType = DocumentTypes.Workflow;
                    else if (entity is Solution) docType = DocumentTypes.Solution;
                    SaveWindow window = new SaveWindow(docType, entity.Name.Replace("*", String.Empty));
                    window.Owner = this;
                    if (window.ShowDialog().Value)
                    {
                        if (window.rbFileSystem.IsChecked.Value)
                        {
                            entity.ClearId();
                            entity.FileName = window.edtFileName.Text;
                            entity.Serialize().Save(entity.FileName);
                            entity.Modified = false;
                        }
                        else if (window.rbDatabase.IsChecked.Value)
                        {
                            entity.CreateId();
                            entity.FileName = window.edtDatabaseName.Text;
                            DataAccess.Insert(entity.Id, entity.FileName, entity.Serialize().ToString(), docType.ToString());
                            entity.Modified = false;
                        }
                        if (entity is Workflow)
                            (entity as Workflow).Parent.Modified = true;
                    }
                }
                //saving to Sql Server
                else if (entity.Id != Guid.Empty)
                {
                    if (DataAccess.CheckExists(entity.Id))
                        DataAccess.Update(entity.Id, entity.Serialize().ToString());
                    else
                        SaveEntity(entity, true);
                    entity.Modified = false;
                }
                //saving to file
                else if (!String.IsNullOrEmpty(entity.FileName))
                {
                    entity.Serialize().Save(entity.FileName);
                    entity.Modified = false;
                }
                //saving as new if no options of the above worked
                else
                {
                    SaveEntity(entity, true);
                    return;
                }
                entity.Name = String.Empty; //for triggering OnPropertyChanged
            }
            catch (Exception ex)
            {
                entity.Log.AddLog(LogMessageType.Error, ex.Message);
            }
        }
    }
}
